// DIBImage.cpp: implementation of the CDIBImage class.
//This is a program special for operation of DIB bitmap
//Written By WeiXinGuo   2000.11
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DIBImage.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_SERIAL(CDIBImage, CObject, 0);

CDIBImage::CDIBImage()
{
	m_lpImage=NULL;
	m_lpBih=NULL;
	m_hPal=NULL;
	m_lpColorTable=NULL;
	m_filename.Empty();

}

CDIBImage::~CDIBImage()
{
	Empty();

}

void CDIBImage::Empty()
{
	if(m_lpImage!=NULL)
	{
		delete[] m_lpImage;
		m_lpImage=NULL;
	}
	if(m_lpBih!=NULL)
	{
		delete[] m_lpBih;
	    m_lpBih=NULL;
	}
	if(m_hPal!=NULL)
	{
		DeleteObject(m_hPal);	
	}
}

int CDIBImage::ComputeColorNum()
{
	ASSERT(m_lpBih!=NULL);
	int ColorUsed=m_lpBih->biClrUsed;
	if(ColorUsed!=0)
		return ColorUsed;
	int BitCount;
	BitCount=m_lpBih->biBitCount;
	switch (BitCount)
	{
		case 1:
			return 2;

		case 4:
			return 16;

		case 8:
			return 256;

		default:
			return 0;
	}
}

BOOL CDIBImage::CreatImagePalette()
{
	int numColor=ComputeColorNum();
	if(numColor==0)
		return FALSE;
	if(m_lpColorTable==NULL)
	{
		LPBYTE lpcolor=(LPBYTE)m_lpBih+sizeof(BITMAPINFOHEADER);
		m_lpColorTable=LPRGBQUAD(lpcolor);
	}
	LPLOGPALETTE lpPal;
	BOOL bResult=FALSE;
	lpPal=(LPLOGPALETTE)new char[2 * sizeof(WORD)+ sizeof(PALETTEENTRY)*numColor];
	if(lpPal==NULL)
		return FALSE;
	lpPal->palVersion = 0x300;
	lpPal->palNumEntries = numColor;
	for(int i=0; i<numColor; i++)
	{
			
		lpPal->palPalEntry[i].peRed =m_lpColorTable[i].rgbRed;
		lpPal->palPalEntry[i].peGreen =m_lpColorTable[i].rgbGreen;
		lpPal->palPalEntry[i].peBlue = m_lpColorTable[i].rgbBlue;
		lpPal->palPalEntry[i].peFlags =0;
	}
	 m_hPal=::CreatePalette(lpPal);
	delete[] lpPal;
	return TRUE;
}

int CDIBImage::GetWidth()
{
	ASSERT(m_lpBih!=NULL);
	return m_lpBih->biWidth;

}

int CDIBImage::GetHeight()
{
	ASSERT(m_lpBih!=NULL);
	return m_lpBih->biHeight;

}

int CDIBImage::WidthBytes()
{
	ASSERT(m_lpBih!=NULL);
	return WIDTHBYTES(m_lpBih->biWidth*m_lpBih->biBitCount);

}

BOOL CDIBImage::Draw(HDC hDC,LPRECT lpDCRect,LPRECT lpDIBRect)
{
	BOOL     bSuccess=FALSE;      
	HPALETTE hOldPal=NULL;       

	if (m_lpImage == NULL||m_lpBih==NULL)
		return FALSE;
	if (m_hPal != NULL)
	{
		hOldPal = ::SelectPalette(hDC, m_hPal, TRUE);
	}
    ::RealizePalette(hDC);
	::SetStretchBltMode(hDC, COLORONCOLOR);

	if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDIBRect)) &&
	   (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
		bSuccess = ::SetDIBitsToDevice(hDC,                  
								   lpDCRect->left,             
								   lpDCRect->top,             
								   RECTWIDTH(lpDCRect),       
								   RECTHEIGHT(lpDCRect),       
								   lpDIBRect->left,           
								   m_lpBih->biHeight -
								   lpDIBRect->top -
								   RECTHEIGHT(lpDIBRect),  
								   0,                         
								   m_lpBih->biHeight,  
								   m_lpImage,                
								   (LPBITMAPINFO)m_lpBih,     
								   DIB_RGB_COLORS);           
   else
	  bSuccess = ::StretchDIBits(hDC,                         
							   lpDCRect->left,                 
							   lpDCRect->top,                  
							   RECTWIDTH(lpDCRect),           
							   RECTHEIGHT(lpDCRect),           
							   lpDIBRect->left,                
							   lpDIBRect->top,                 
							   RECTWIDTH(lpDIBRect),           
							   RECTHEIGHT(lpDIBRect),          
							   m_lpImage,                      
							   (LPBITMAPINFO)m_lpBih,         
							   DIB_RGB_COLORS,                 
							   SRCCOPY);                       

	if (hOldPal != NULL)
	{
		::SelectPalette(hDC, hOldPal, TRUE);
	}

   return bSuccess;
}

BOOL CDIBImage::Read(CFile &file)
{
	if(!IsEmpty())
	Empty();
	int nCount, nSize;
	m_filename=file.GetFilePath();
	BITMAPFILEHEADER bmfh;
	try 
	{
		nCount = file.Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
		if(nCount != sizeof(BITMAPFILEHEADER)) 
		{
		}
		if(bmfh.bfType != 0x4d42) 
		{
		}
		nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
		m_lpBih = (LPBITMAPINFOHEADER) new char[nSize];
		nCount = file.Read(m_lpBih, nSize);
		if(ComputeColorNum()!=0)
		{
			CreatImagePalette();
		}
		m_lpImage = (LPBYTE) new char[WidthBytes()*GetHeight()];
		nCount = file.Read(m_lpImage,WidthBytes()*GetHeight()); // image only
	}
	catch(CException* pe) 
	{
		AfxMessageBox("Read error");
		pe->Delete();
		return FALSE;
	}
	m_filename=file.GetFilePath();

	return TRUE;

}

BOOL CDIBImage::Write(CFile &file)
{
	DWORD dwBinfoSize=0,dwImageSize=0;
    BITMAPFILEHEADER bmfHdr;
	if (m_lpImage==NULL||m_lpBih==NULL)
		return FALSE;

	bmfHdr.bfType = 0x4d42;  

	dwBinfoSize= sizeof(BITMAPINFOHEADER)+ComputeColorNum()*sizeof(RGBQUAD);  // Partial Calculation

	if ((m_lpBih->biCompression == BI_RLE8) || (m_lpBih->biCompression == BI_RLE4))
	{
		dwImageSize +=m_lpBih ->biSizeImage;
	}
	else
	{
		
		dwImageSize= WidthBytes() * m_lpBih->biHeight;
		
		m_lpBih->biSizeImage = dwImageSize;
	}

	bmfHdr.bfSize = dwImageSize+dwBinfoSize+ sizeof(BITMAPFILEHEADER);
	bmfHdr.bfReserved1 = 0;
	bmfHdr.bfReserved2 = 0;

	bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + m_lpBih->biSize
						+ ComputeColorNum()*sizeof(RGBQUAD);

	try
	{
		file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
		file.Write((LPVOID)m_lpBih,dwBinfoSize);
		file.Write((LPVOID)m_lpImage,dwImageSize);
	}
    catch(CException* pe) 
	{
		AfxMessageBox("Write error");
		pe->Delete();
		return FALSE;
	}
	m_filename=file.GetFilePath();

	return TRUE;

}

BOOL CDIBImage::IsEmpty()
{
	if(m_lpImage==NULL||m_lpBih==NULL)
		return TRUE;
	else
		return FALSE;

}

HBITMAP CDIBImage::CreateBitmap(CDC *pDC)
{
	if (IsEmpty()) 
		return NULL;
    HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_lpBih,
            CBM_INIT, m_lpImage, (LPBITMAPINFO) m_lpBih, DIB_RGB_COLORS);
    ASSERT(hBitmap != NULL);
    return hBitmap;
}

void CDIBImage::Serialize(CArchive &ar)
{
	ar.Flush();
	if(ar.IsStoring()) 
	{
		Write(*ar.GetFile());
	}
	else 
	{
		Read(*ar.GetFile());
	}

}
void CDIBImage::Threshold(int thresh)
{
	if(IsEmpty())
		return;
	else if(m_lpBih->biBitCount!=8)
	{
		AfxMessageBox("The format of the image is not supported!");
		return;
	}
	int width=WIDTHBYTES(m_lpBih->biWidth*8);
	int u,v;
	for(DWORD ii=0;ii<(unsigned long)width*m_lpBih->biHeight;ii++)
	{
        u=ii%width;
		v=ii/width;
		if(u<m_lpBih->biWidth)
		{
				if(*(m_lpImage+ii)>thresh)				
					*(m_lpImage+ii)=255;
				else
					*(m_lpImage+ii)=0;									
		}
	}
	
}

void CDIBImage::MorphErosion(BOOL m_struct[3][3])
{
	int i,j,m,n;
	int h=m_lpBih->biHeight;
	int w=m_lpBih->biWidth;
	int width=WIDTHBYTES(m_lpBih->biWidth*8);

	LPBYTE newdata=new BYTE[h*width];
	LPBYTE dst;
	LPBYTE ori;
	BYTE pixel;
	for(i=1;i<h-1;i++)
		for(j=1;j<w-1;j++)
		{
			ori=m_lpImage+i*width+j;
			dst=newdata+i*width+j;
			*dst=*ori;
			for(m=0;m<3;m++)
				for(n=0;n<3;n++)
				{
					if(!m_struct[m][n])
						continue;
					pixel=*(ori+((2-m)-1)*width+(n-1));
					if(pixel==0)
						*dst=0;
				}

		}
	delete[] m_lpImage;
	m_lpImage=newdata;

}

void CDIBImage::MorphDilation(BOOL m_struct[3][3])
{
	int i,j,m,n;
	int h=m_lpBih->biHeight;
	int w=m_lpBih->biWidth;
	int width=WIDTHBYTES(m_lpBih->biWidth*8);

	LPBYTE newdata=new BYTE[h*width];
	LPBYTE dst;
	LPBYTE ori;
	BYTE pixel;
	for(i=1;i<h-1;i++)
		for(j=1;j<w-1;j++)
		{
			ori=m_lpImage+i*width+j;
			dst=newdata+i*width+j;
			*dst=*ori;
			for(m=0;m<3;m++)
				for(n=0;n<3;n++)
				{
					if(!m_struct[m][n])
						continue;
					pixel=*(ori+((2-m)-1)*width+(n-1));
					if(pixel==255)
						*dst=255;
				}

		}
	delete[] m_lpImage;
	m_lpImage=newdata;

}
